package ktvdownloadserver

import (
	"bytes"
	"encoding/binary"
	"fmt"
	"ktvserver/core/tcpserver"
	"ktvserver/ktvutil"
	"log"
	"os"
	"path/filepath"
)

// 获取超过指定编号的歌曲资料
func KtvPublicBeyondNumberSongData(w tcpserver.ResponseWriter, req *tcpserver.Request) {

	ktvinfo := tcpserver.GetKtvRequestInfo(req.DataBody)

	// 获取下载令牌
	token := uint64(ktvinfo.FastForward) | uint64(ktvinfo.FFLength)<<32
	req.SetToken(token)

	// 获取指定编号以上的歌曲资料列表
	strSongDataPath := filepath.Join("SYSTEM", "SONGDATA.DAT")     // 歌曲数据路径
	strSingerDataPath := filepath.Join("SYSTEM", "SINGERDATA.DAT") // 歌星数据路径

	songList := LoadSongInfoBeyondNumber(ktvinfo.Number, strSongDataPath, strSingerDataPath)
	data, ok := GetBytesFromSongInfo(songList)

	if ok {

		// 数据正确, 写入响应数据
		log.Printf("(%v) NewSyncSongData, number=%d, songCount=%d, len(data)=%d",
			req.RemoteIP(),
			ktvinfo.Number,
			len(songList),
			len(data),
		)

		tcpserver.WriteHeader(w, uint32(len(data)), 0)
		w.Write(data)
		tcpserver.WriteFooter(w)
	} else {
		// 内部错误，返回空数据
		log.Printf("(%v) NewSyncSongData, number=%d, songCount=%d, error",
			req.RemoteIP(),
			ktvinfo.Number,
			len(songList),
		)

		tcpserver.WriteHeader(w, 0, 0)
		tcpserver.WriteFooter(w)
	}

}

const KTV_ALL_SINGER_NAME_MAX_LENGTH = (100)

//  KTV歌曲的所有数据
type KtvSongTotalData struct {
	ktvutil.KtvSongData
	Singer_name [KTV_ALL_SINGER_NAME_MAX_LENGTH]uint16
}

// 返回结构体大小
func (std *KtvSongTotalData) GetStructSize() uint32 {
	return 56 + 200
}

// 歌曲资料, 保护歌曲名称
type KtvSongInfo struct {
	Data   ktvutil.KtvSongData
	Title  []uint16 // 歌曲名
	Artist string   // 歌星名
}

// 加载歌曲资料
func LoadSongInfoBeyondNumber(number uint32, strSongDataPath string, strSingerDataPath string) []KtvSongInfo {

	myList := []KtvSongInfo{}

	// 加载歌星的资料
	mapSingerIdAndName, ok := LoadSingerNumberAndNameList(strSingerDataPath)
	if ok != true {
		return myList
	}

	// 读取全部歌曲的数据到内存
	f, err := os.Open(strSongDataPath)
	if err != nil {
		log.Printf("OPEN SONGDATA.DAT ERR=%v", err)
		return myList
	}

	defer f.Close()

	fi, _ := f.Stat()
	if fi.Size() <= 0 {
		return myList
	}

	data := make([]byte, fi.Size())
	f.Read(data)

	rd := bytes.NewReader(data)

	// 分析数据开始
	var copyright ktvutil.DatCopyright

	binary.Read(rd, binary.LittleEndian, &copyright)
	if copyright.IsShiyou() != true {
		return myList
	}

	// 拼接歌星名, 内置的函数
	JoinSingerNameFunc := func(idList []uint16) string {
		strResult := ""
		idLen := len(idList)
		if idLen > 4 {
			idLen = 4
		}

		for j := 0; j < idLen; j++ {
			if idList[j] <= 0 {
				break
			}
			name, found := mapSingerIdAndName[idList[j]]
			if found {
				if strResult == "" {
					strResult = name
				} else {
					strResult = fmt.Sprintf("%s,%s", strResult, name)
				}
			}
		} // end for
		return strResult
	}

	// 添加路径到map
	var i uint32

	for i = 0; i < copyright.RecordCount; i++ {

		var songInfo KtvSongInfo

		recordOffset := ktvutil.GetCopyrightStructLength() + songInfo.Data.GetStructSize()*i

		// 检查是否越界
		if recordOffset >= uint32(fi.Size()) {
			break
		}

		// 偏移到指定的位置, 读取SongData记录
		rd.Seek(int64(recordOffset), 0)
		binary.Read(rd, binary.LittleEndian, &(songInfo.Data))

		/*
			log.Printf("Number=%d,NameStart=%d, NameLength=%d",
				songInfo.Data.SongNum,
				songInfo.Data.NameStart,
				songInfo.Data.NameLength)
		*/

		if songInfo.Data.SongNum <= number {
			continue
		}

		// 检查歌名数据是否出错
		if songInfo.Data.NameStart+songInfo.Data.NameLength >= uint32(fi.Size()) || songInfo.Data.NameLength == 0 {
			continue
		}

		//
		titleWord := []uint16{}
		rd.Seek(int64(songInfo.Data.NameStart), 0)
		var j uint32

		for j = 0; j < (songInfo.Data.NameLength / 2); j++ {
			var ch uint16
			binary.Read(rd, binary.LittleEndian, &ch)
			if ch == 0 {
				break
			}
			titleWord = append(titleWord, ch)
		} // end for

		//title := syscall.UTF16ToString(titleWord)
		//log.Printf("Number=%d, title=%s, len(titleWord)=%d", songInfo.Data.SongNum, title, len(titleWord))

		songInfo.Title = titleWord

		// 获取歌星名称列表
		songInfo.Artist = JoinSingerNameFunc(songInfo.Data.SingerNum[:])

		myList = append(myList, songInfo)

	} // end for RecordCount

	return myList

}

// 将KtvSongInfo转换
func GetBytesFromSongInfo(songInfo []KtvSongInfo) ([]byte, bool) {

	count := len(songInfo)

	//log.Printf("GetBytesFromSongInfo, count=%d", count)

	var copyright ktvutil.DatCopyright
	var wordEnd []byte = []byte{0x00, 0x00}

	buf := new(bytes.Buffer)

	copyright.Reset()
	copyright.RecordCount = uint32(count)
	copyright.Version = 0

	// 如果数量为零，直接返回
	if count <= 0 {
		binary.Write(buf, binary.LittleEndian, &copyright)
		return buf.Bytes(), true
	}

	// 先计算数据长度
	var totalLen uint32 = 0
	var totalSongData KtvSongTotalData

	totalLen = copyright.GetStructSize() + uint32(count)*totalSongData.GetStructSize()
	for i := 0; i < count; i++ {
		totalLen += songInfo[i].Data.NameLength
		totalLen += 2 // 附加两个空白的字节
	}

	//log.Printf("totalLen=%d", totalLen)

	copyright.FileSize = totalLen

	// 计算歌曲名称的偏移
	if count > 0 {
		songInfo[0].Data.NameStart = copyright.GetStructSize() + uint32(count)*totalSongData.GetStructSize()
		for i := 0; i < count-1; i++ {
			NextStart := songInfo[i].Data.NameStart + songInfo[i].Data.NameLength + 2
			songInfo[i+1].Data.NameStart = NextStart
		}
	}

	// 开始写入数据

	// 写入copyrigh
	binary.Write(buf, binary.LittleEndian, copyright)

	// 写入TotalSongData
	for i := 0; i < count; i++ {
		tsd := songInfoToTotalSongData(songInfo[i])
		binary.Write(buf, binary.LittleEndian, tsd)
	}

	// 写入歌名
	for i := 0; i < count; i++ {
		binary.Write(buf, binary.LittleEndian, songInfo[i].Title)
		buf.Write(wordEnd)
	}

	//log.Printf("buf len=%d, totallen=%d", buf.Len(), totalLen)

	// 需要校验缓冲区的大小是否和计算值一致
	if uint32(buf.Len()) != totalLen {
		log.Printf("GetBytesFromSongInfo, Length Mismatch, buflen=%d,  totalLen=%d", buf.Len(), totalLen)
		return nil, false
	}

	return buf.Bytes(), true
}

// 类型转换
func songInfoToTotalSongData(info KtvSongInfo) KtvSongTotalData {
	var result KtvSongTotalData

	// 直接赋值
	result.KtvSongData = info.Data

	// 转换歌星名
	singerName := ktvutil.StringToUtf16(info.Artist)
	for i := 0; i < len(singerName); i++ {
		if i >= 99 {
			break
		}
		result.Singer_name[i] = singerName[i]

	} // end for

	return result
}

// 歌星资料

// 歌星资料库
type KtvSingerInfo struct {
	Singer_name          [20]uint16 // 40
	Singer_py            [10]uint16 // 20
	Singer_Num           uint16     // 歌星编号
	Padding              uint16     // 附加消息
	Singer_Click         uint32     //
	Singer_Pic_start_add uint32     // 歌星图片开始地址
	Singer_Pic_Length    uint32     // 歌星图片长度
	Singer_Display       byte
	Singer_Category      byte
	Singer_Area          byte
	Reserved             byte
}

func (s *KtvSingerInfo) GetStructSize() uint32 {
	return 80
}

// 加载歌星的编号和名称列表
func LoadSingerNumberAndNameList(strFilePath string) (map[uint16]string, bool) {

	f, err := os.Open(strFilePath)
	if err != nil {
		return nil, false
	}

	defer f.Close()

	//
	// 分析数据开始
	var copyright ktvutil.DatCopyright
	binary.Read(f, binary.LittleEndian, &copyright)
	if copyright.IsShiyou() != true {
		return nil, false
	}

	//
	log.Printf("Singer, TotalCount=%d", copyright.RecordCount)

	if copyright.RecordCount <= 0 {
		return nil, false
	}

	var info KtvSingerInfo

	// 创建缓冲区
	bufLen := info.GetStructSize() * copyright.RecordCount
	buf := make([]byte, bufLen)
	readBytes, err := f.Read(buf)
	if err != nil || readBytes != int(bufLen) {
		return nil, false
	}

	rd := bytes.NewReader(buf)

	mapNumberAndName := make(map[uint16]string)

	// 开始解析数据
	var i uint32
	for i = 0; i < copyright.RecordCount; i++ {

		var singer KtvSingerInfo
		binary.Read(rd, binary.LittleEndian, &singer)
		name := ktvutil.Utf16ToUtf8(singer.Singer_name[:])
		// 记录到map
		mapNumberAndName[singer.Singer_Num] = name

	}

	return mapNumberAndName, true
}

////////////////////////////////////////////////////////////////////////////
// 返回空的资料数据
// 禁止旧版本的点歌机程序同步歌库
func KtvPublicBeyondNumberSongDataEmpty(w tcpserver.ResponseWriter, req *tcpserver.Request) {

	ktvinfo := tcpserver.GetKtvRequestInfo(req.DataBody)

	// 获取下载令牌
	token := uint64(ktvinfo.FastForward) | uint64(ktvinfo.FFLength)<<32
	req.SetToken(token)

	// 数据正确, 写入响应数据
	log.Printf("(%v) OLD SyncSongData, number=%d", req.RemoteIP(), ktvinfo.Number)

	myNewSongList := []KtvSongInfo{}

	data, ok := GetBytesFromSongInfo(myNewSongList)

	if ok {

		tcpserver.WriteHeader(w, uint32(len(data)), 0)
		w.Write(data)
		tcpserver.WriteFooter(w)

	} else {

		tcpserver.WriteHeader(w, 0, 0)
		tcpserver.WriteFooter(w)
	}

}
